﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ACS;
using ACS.NDEF;
using System.Diagnostics;
namespace NFC_Tag_Management
{
    public partial class mainNFC : Form
    {


        PcscItem pcscConnection;
        PcscMifare objMifare;
        PcscUlc objUltralighC;
        Acr1222U objAcr122U;
        int returnCode;
        CHIP_TYPE currentCard;
        string uri_Value;
        Boolean readStatus = false;
        DataTable dtbl = new nfc.dataModel.DSTagInformation.DataCustomerDataTable();
         public mainNFC()
        {
            InitializeComponent();
            pcscConnection = new PcscItem();
            pcscConnection.onReceivedCommand += new TransmitApduHandler(pcscConnection_OnReceivedCommand);
            pcscConnection.onSendCommand += new TransmitApduHandler(pcscConnection_OnSendCommand);
            resetFields();
        }
        private void mainNFC_Load(object sender, EventArgs e)
        {
            
            initializeCard();
            lblValueNFCCard.Text = "";
            nfc_value(txtName.Text, txtNRIC.Text, txtMobile.Text);
            TimerManager.Start();
        }
        
        private void nfc_value(string name, string nric, string mobile)
        {
            uri_Value = "127.0.0.1:8080/netQ/netqpost.aspx?function=MDI&counter=1&userID=admin&name=" + name + "&nric=" + nric + "&handphone=" + mobile + "&services=3&queue=&printer=1&SinglePrint=Y";
            txtURI.Text = uri_Value;
        }
       
        private void initializeCard()
        {
           
           
         
            returnCode = pcscConnection.establishContext();
            if (returnCode != PCSCProvider.SCARD_S_SUCCESS)
            {
                MessageBox.Show("Unable to establish context.\r\n" + PCSCProvider.GetScardErrMsg(returnCode), "Failed");

            }

            
        }
        private Boolean  reloadReaders()
        {
           
            //Get all connected smartcard reader
            string[] readers = pcscConnection.getAllReaders();
            if (readers.Length== 0)
            {
                lblNFCName.Text = "No Reader";
                lblNFCName1.Text = "";
                return false;
            }
            else {
                //ComboBoxSmartCardReaders.Items.Clear();
                lblNFCName.Text = "";
                              
                for (int i = 0; i < readers.Length; i++){
                    //ComboBoxSmartCardReaders.Items.Add(readers[i]);
                    lblNFCName.Text ="NFC Reader: " + readers[i];
                    lblNFCName1.Text = readers[i];

                //if (ComboBoxSmartCardReaders.Items.Count > 0)
                //    ComboBoxSmartCardReaders.SelectedIndex = 1;
                }
                //displayMessage("Card: ");
                return true; 
            }
            
        }
        private Boolean connectTocard(String cardName)
        {
            if (cardName == "")
            {
                //MessageBox.Show("Please select reader", "Select Reader");
                return false;
            }
            returnCode = pcscConnection.connect(cardName);
            if (returnCode != PCSCProvider.SCARD_S_SUCCESS)
            {
                //MessageBox.Show("Unable to connect to reader.\r\n" + PCSCProvider.GetScardErrMsg(returnCode), "Connect Failed");
                return false;
            }
            else
            {
                //displayMessage("Connected To:\r\n" + lblNFCName.Text);

                objAcr122U = new Acr1222U(pcscConnection);

                currentCard = objAcr122U.getChipType();

                switch (currentCard)
                {
                    case CHIP_TYPE.MIFARE_1K:
                    case CHIP_TYPE.MIFARE_4K:
                        {
                            objMifare = new PcscMifare(pcscConnection);
                            GroupBoxKeys.Enabled = true;
                            break;
                        }
                    case CHIP_TYPE.MIFARE_ULTRALIGHT:
                        {
                            objUltralighC = new PcscUlc(pcscConnection);

                            GroupBoxKeys.Enabled = false;
                            break;
                        }
                    default:
                        {
                            MessageBox.Show("Card not supported");
                            return false;
                        }
                }
                //displayMessage("Card: " + currentCard.ToString());
             return true;

                //ButtonInitializeMifareCard.Enabled = true;
                //ButtonReadFromCard.Enabled = true;
                //ButtonResetCard.Enabled = true;

            }

        }


        void pcscConnection_OnReceivedCommand(object sender, transmitApduEventArg e)
        {
            //MessageBox.Show(">  ReceivedCommand "+ e.data.ToString());
            displayMessage(">  ReceivedCommand ", e.data, "\r\n", e.data.Length);
        }
        void pcscConnection_OnSendCommand(object sender, transmitApduEventArg e)
        {
            //MessageBox.Show("<  SendCommand " + e.data.ToString());
            displayMessage("<  SendCommand ", e.data, "", e.data.Length);
        }

        public void displayMessage(string prefixStr, byte[] buff, string postfixStr, int buffLen)
        {
            string tmpStr = "";

            if (buff.Length < buffLen)
                return;

            tmpStr = string.Empty;

            //Convert each byte from buff to its string representation.
            for (int i = 0; i < buffLen; i++)
                tmpStr += string.Format("{0:X2}", buff[i]) + " ";


            displayMessage(prefixStr + tmpStr + postfixStr);
        }
        void resetFields()
        {
            //lblStatus.Text = "";
            //ComboBoxSmartCardReaders.Items.Clear();

            MaskedTextBoxMadKeyB.Text = "FFFFFFFFFFFF";
            MaskedTextBoxNfcForumSectorKeyB.Text = "FFFFFFFFFFFF";

            //TextBoxTextMessage.Text = "Advanced Card System Ltd.";

            //ComboBoxSmartPosterAction.SelectedIndex = 0;
            //ComboBoxSmartPosterPrefixURI.SelectedIndex = 0;
            //ComboBoxSmartPosterTitleLanguage.SelectedIndex = 0;
            //ComboBoxTextLanguage.SelectedIndex = 0;
            ComboBoxURIPrefix.SelectedIndex = 3;

            //ButtonConnect.Enabled = false;
            //ButtonInitializeMifareCard.Enabled = false;
            //ButtonReadFromCard.Enabled = false;
            //ButtonResetCard.Enabled = false;
        }

        private void BtnWriteToCard_Click(object sender, EventArgs e)
        {
            RichTextBoxApduCommandLogs.Text = "";
            if (Helper.ValidateTextField(txtName, "Name", errRequrement) == false) return;
            if (Helper.ValidateTextField(txtNRIC, "NRIC", errRequrement) == false) return;
            if (Helper.ValidateTextField(txtMobile, "Mobile", errRequrement) == false) return;
            if (Helper.ValidateTextField(txtURI, "URI", errRequrement) == false) return;
            switch (currentCard)
            {
                case CHIP_TYPE.MIFARE_1K:
                case CHIP_TYPE.MIFARE_4K:
                    {
                        writeToCard();
                        break;
                    }
                case CHIP_TYPE.MIFARE_ULTRALIGHT:
                    {
                        writeToUltralighCCard();
                        break;
                    }
            }

           
            DataRow drow = dtbl.NewRow();
            drow["CUS_NAME"] = txtName.Text.ToString();
            drow["CUS_NRIC"] = txtNRIC.Text.ToString();
            drow["CUS_MOBILE"] = txtMobile.Text.ToString();
            drow["CUS_URI"] = txtURI.Text.ToString();
            drow["EcodeURI"] = RichTextBoxEncodedNdefMessage.Text.ToString();
            dtbl.Rows.Add(drow);
            dataGridView1.DataSource = dtbl;

        }
        readonly byte[] MIFARE_TRANSPORT_KEY = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
        readonly byte[] NDEF_PUBLIC_KEY_A_NFC_FORUM_SECTOR = new byte[] { 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7 };
        readonly byte[] NDEF_SECTOR_TRAILER_NFC_FORUM_SECTOR = new byte[] { 0x7F, 0x07, 0x88, 0x40 };
        readonly byte[] NDEF_PUBLIC_KEY_A_MAD_SECTOR = new byte[] { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5 };
        readonly byte[] NDEF_SECTOR_TRAILER_MAD_SECTOR = new byte[] { 0x78, 0x77, 0x88, 0xC1 };

        void writeToUltralighCCard()
        {
            byte numberOfPagesNeeded;
            byte physicalStartPageToWrite = 4;
            byte pageNumber;
            byte[] madSector = new byte[0];
            byte[] dataToWrite = new byte[0];
            byte[] arrLength;
            byte[] buffer;
            byte[] data;
            int padding = 0;
            int dataLength;

            try
            {
                if (RichTextBoxEncodedNdefMessage.Text.Trim() == "")
                {
                    MessageBox.Show("There are no NDEF message to write");
                    return;
                }

                dataToWrite = Helper.getBytes(RichTextBoxEncodedNdefMessage.Text);
                if (dataToWrite.Length < 1)
                {
                    if (RichTextBoxEncodedNdefMessage.Text.Trim() == "")
                    {
                        MessageBox.Show("There are no NDEF message to write");
                        return;
                    }
                }


                if (dataToWrite.Length > 132)
                {
                    MessageBox.Show("NDEF Message is too large");
                    return;
                }

                objUltralighC = new PcscUlc(pcscConnection);


                //Form the data to be written to the card
                buffer = new byte[0];

                //Lock Control TLV

                buffer = Helper.appendArrays(buffer, new byte[] { 0x01, 0x03, 0xA0, 0x10, 0x44 });
                if (dataToWrite.Length < 255)
                {
                    //If data is less than or equal to 254 (0xFE) use one byte format
                    //Refere to NXP Type MF1K/4K Tag Operation document
                    //http://www.nxp.com/
                    buffer = Helper.appendArrays(buffer, new byte[] { (byte)NFCForum.TAGs.NDEF_MESSAGE_TLV, (byte)dataToWrite.Length });
                }
                else
                {
                    //If data is greater than 254 (0xFE) use 3 bytes format
                    dataLength = dataToWrite.Length;

                    //In 3 bytes format the last 2 bytes is for 00FE - FFFF                    
                    dataLength -= 254;

                    arrLength = new byte[3];

                    //Indicates that two more bytes folow
                    arrLength[0] = 0xFF;
                    arrLength[1] = (byte)((dataLength & 0xFF00) >> 8);
                    arrLength[2] = (byte)(dataLength & 0xFF);

                    //NDEF Message TAG
                    buffer = Helper.appendArrays(buffer, (byte)NFCForum.TAGs.NDEF_MESSAGE_TLV);

                    //length
                    buffer = Helper.appendArrays(buffer, arrLength);

                }

                buffer = Helper.appendArrays(buffer, dataToWrite);

                //Append Terminator TLV
                buffer = Helper.appendArrays(buffer, (byte)NFCForum.TAGs.TERMINATOR_TLV);

                if ((buffer.Length % 4) != 0)
                    padding = (4 - (buffer.Length % 4));
                else
                    padding = 0;

                buffer = Helper.appendArrays(buffer, new byte[padding]);

                //Write the data to Mifare Card
                //Start from NFC Form Sector 1 Block 0

                displayTitle("Write NDEF Message To Card");

                displayMessage("\r\n", buffer, "\r\nLength:" + buffer.Length.ToString(), buffer.Length);

                //Get mumber of blocks needed
                // MAD sector blocks not included
                numberOfPagesNeeded = (byte)((double)Math.Ceiling(buffer.Length / 4.00));

                for (int page = 0; page < numberOfPagesNeeded; page++)
                {
                    data = buffer.Skip(page * 4).Take(4).ToArray();
                    objUltralighC.updateBinaryBlock((byte)(page + physicalStartPageToWrite), data);
                }


                //Write Capability Counter
                //Page 3 (OTP)
                displayTitle("Write Capability Counter (Permanent)");
                data = new byte[4];
                data[0] = 0xE1; //Magic Number
                data[1] = 0x10; //NFC Forum Type 2 Tag Operational Version Number
                data[2] = 0x12; //144 bytes (36 pages) of data area - Page 3-39
                data[3] = 0x00; //Read/Write access capability without any security

                objUltralighC.updateBinaryBlock(3, data);

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        void writeToCard()
        {
            try
            {
                Acr1222U objACR122U;
                byte[] madSector = new byte[0];
                byte[] dataToWrite = new byte[0];
                byte[] madKeyB, nfcKeyB;
                byte[] arrLength;
                byte[] buffer;
                byte numberOfNfcForumSector = 0;
                byte numberOfBlocksNeeded = 0;
                byte lastSectorAuthenticated = 0;
                byte physicalBlockToWrite = 0x04;
                byte sectorTrailer = 0x03;

                int dataLength;

                if (RichTextBoxEncodedNdefMessage.Text.Trim() == "")
                {
                    MessageBox.Show("There are no NDEF message to write");
                    return;
                }

                dataToWrite = Helper.getBytes(RichTextBoxEncodedNdefMessage.Text);
                if (dataToWrite.Length < 1)
                {
                    if (RichTextBoxEncodedNdefMessage.Text.Trim() == "")
                    {
                        MessageBox.Show("There are no NDEF message to write");
                        return;
                    }
                }


                madKeyB = Helper.getBytes(MaskedTextBoxMadKeyB.Text);
                if (madKeyB.Length != 6)
                {
                    MessageBox.Show("Key-in valid MAD Key B");
                    MaskedTextBoxMadKeyB.Focus();
                    return;
                }

                nfcKeyB = Helper.getBytes(MaskedTextBoxNfcForumSectorKeyB.Text);
                if (nfcKeyB.Length != 6)
                {
                    MessageBox.Show("Key-in valid NFC Forum Sector Key B");
                    MaskedTextBoxNfcForumSectorKeyB.Focus();
                    return;
                }


                objACR122U = new Acr1222U(pcscConnection);


                displayTitle("Get Chip Type");
                CHIP_TYPE chipType = objACR122U.getChipType();
                displayMessage(chipType.ToString() + "\r\n");

                if (chipType != CHIP_TYPE.MIFARE_1K && chipType != CHIP_TYPE.MIFARE_4K)
                {
                    MessageBox.Show("Card not supported");
                    return;
                }

                displayMessage("Load Authentication Key");
                if (!objACR122U.loadAuthKey(MIFARE_TRANSPORT_KEY, 0x00))
                {
                    MessageBox.Show("Unable to load key", "Load Key Failed");
                    return;
                }

                //Form the data to be written to the card
                buffer = new byte[0];
                if (dataToWrite.Length < 255)
                {
                    //If data is less than or equal to 254 (0xFE) use one byte format
                    //Refere to NXP Type MF1K/4K Tag Operation document
                    //http://www.nxp.com/
                    buffer = Helper.appendArrays(buffer, new byte[] { (byte)NFCForum.TAGs.NDEF_MESSAGE_TLV, (byte)dataToWrite.Length });
                }
                else
                {
                    //If data is greater than 254 (0xFE) use 3 bytes format
                    dataLength = dataToWrite.Length;

                    //In 3 bytes format the last 2 bytes is for 00FE - FFFF                    
                    dataLength -= 254;

                    arrLength = new byte[3];

                    //Indicates that two more bytes folow
                    arrLength[0] = 0xFF;
                    arrLength[1] = (byte)((dataLength & 0xFF00) >> 8);
                    arrLength[2] = (byte)(dataLength & 0xFF);

                    //NDEF Message TAG
                    buffer = Helper.appendArrays(buffer, (byte)NFCForum.TAGs.NDEF_MESSAGE_TLV);

                    //length
                    buffer = Helper.appendArrays(buffer, arrLength);

                }

                buffer = Helper.appendArrays(buffer, dataToWrite);

                //Append Terminator TLV
                buffer = Helper.appendArrays(buffer, (byte)NFCForum.TAGs.TERMINATOR_TLV);


                //Write the data to Mifare Card
                //Start from NFC Form Sector 1 Block 0

                displayTitle("Write NDEF Message To Card");

                //Get mumber of blocks needed
                // MAD sector blocks not included
                numberOfBlocksNeeded = (byte)((double)Math.Ceiling(buffer.Length / 16.00));
                physicalBlockToWrite = 0x04; //Start to write at sector 1 block 1 (Physical Block 0x04)

                for (int indx = 0; indx < numberOfBlocksNeeded; indx++, physicalBlockToWrite++)
                {
                    byte[] tmpArray = new byte[16];
                    int lenToCopy = 16;

                    //Check if remaining data to be copied is less than 16
                    if ((buffer.Length - (indx * 16)) > 16)
                        lenToCopy = 16;
                    else
                        lenToCopy = buffer.Length - (indx * 16);

                    Array.Copy(buffer, (indx * 16), tmpArray, 0, lenToCopy);


                    //Check if sector trailer
                    //If sector trailer skip
                    if (physicalBlockToWrite > 127)
                    {
                        if (((physicalBlockToWrite - 15) % 16) == 0)
                            physicalBlockToWrite++;
                    }
                    else
                    {
                        if (((physicalBlockToWrite - 3) % 4) == 0)
                            physicalBlockToWrite++;

                        //Check if MAD Sector 2 (Sector 16)
                        //if MAD Sector skip
                        if (physicalBlockToWrite >= 64 && physicalBlockToWrite <= 67)
                        {
                            displayMessage("Skip MAD Sector : " + (physicalBlockToWrite / 4).ToString());
                            physicalBlockToWrite = 68; //Move to physical block 68 (Sector 17))
                        }
                    }

                    if (physicalBlockToWrite > 127)
                    {
                        if (lastSectorAuthenticated != (physicalBlockToWrite / 16))
                        {
                            displayMessage("Authenticate Sector: " + (((physicalBlockToWrite - 127) / 16) + 32).ToString());
                            if (!objACR122U.authenticate(physicalBlockToWrite, KEYTYPES.ACR122_KEYTYPE_A, 0x00))
                                throw new Exception("Unable to authenticate in sector " + (physicalBlockToWrite / 16).ToString());

                            lastSectorAuthenticated = (byte)(physicalBlockToWrite / 16);
                        }
                    }
                    else
                    {

                        if (lastSectorAuthenticated != (physicalBlockToWrite / 4))
                        {
                            displayMessage("Authenticate Sector: " + (physicalBlockToWrite / 4).ToString());
                            if (!objACR122U.authenticate(physicalBlockToWrite, KEYTYPES.ACR122_KEYTYPE_A, 0x00))
                                throw new Exception("Unable to authenticate in sector " + (physicalBlockToWrite / 4).ToString());

                            lastSectorAuthenticated = (byte)(physicalBlockToWrite / 4);
                        }
                    }


                    displayMessage("Write in block " + physicalBlockToWrite.ToString());
                    if (objMifare.updateBinaryBlock(physicalBlockToWrite, tmpArray) != 0)
                    {
                        throw new Exception("Unable to update block " + physicalBlockToWrite.ToString());
                    }

                }


                //Initialize MAD Sector
                //If number of sector blocks needed is greater than 120 (30 sectors)
                //31st sector have 15 user blocks (1 - 30 sector have 3 user blocks)
                if (numberOfBlocksNeeded > 120)
                {
                    numberOfNfcForumSector = 30;
                    numberOfNfcForumSector += (byte)(Math.Ceiling((numberOfBlocksNeeded - 120) / 15.00));
                }
                else
                {
                    numberOfNfcForumSector = (byte)(Math.Ceiling(numberOfBlocksNeeded / 3.00));
                }


                madSector = new byte[32];
                for (int i = 0; i < numberOfNfcForumSector; i++)
                {
                    Array.Copy(new byte[] { 0x03, 0xE1 }, 0, madSector, ((i * 2) + 2), 2);

                    //Mad Sector 1 contains 15 AIDs (0-14 = 15)
                    //the rest of the AIDs will bw written in MAD Sector 2
                    if (i == 14)
                        break;
                }

                //Initialize MAD Sector 1

                displayTitle("Initialize MAD Sector 1");

                //Write AIDs to MAD Sector 1
                if (!objACR122U.authenticate(0x01, KEYTYPES.ACR122_KEYTYPE_A, 0x00))
                    throw new Exception("Unable to authenticate in Mifare Application Directory (MAD) sector 1");

                //Write the first 16 bytes (first 7 AIDs) to block 1 of MAD Sector 1 (Sector 0)
                if (objMifare.updateBinaryBlock(0x01, madSector.Take(16).ToArray()) != 0)
                    throw new Exception("Unable to update MAD sector 1");

                //Write next 16 bytes (next 8 AIDs) to block 2 of MAD Sector 1 (Sector 0)
                if (objMifare.updateBinaryBlock(0x02, madSector.Skip(16).Take(16).ToArray()) != 0)
                    throw new Exception("Unable to update MAD sector 1");


                //Initialize MAD Sector 2

                //If number of sectors needed (AIDs) is greater than 15 then write the remaining
                //AIDs in the MAD Sector 2 (Sector 16 of the Mifare Card)
                //MAD Sector 2 can store up to 23 AIDs
                if (numberOfNfcForumSector >= 16 && numberOfNfcForumSector <= 38)
                {
                    displayTitle("Initialize MAD Sector 2");

                    madSector = new byte[48];

                    for (int i = 15; i < numberOfNfcForumSector; i++)
                        Array.Copy(new byte[] { 0x03, 0xE1 }, 0, madSector, ((i - 15) * 2), 2);


                    //Write AIDs to MAD Sector 2 (Sector 16 of the Mifare Card)
                    if (!objACR122U.authenticate(0x40, KEYTYPES.ACR122_KEYTYPE_A, 0x00))
                        throw new Exception("Unable to authenticate in Mifare Application Directory (MAD) sector 2");

                    //Write the first 16 bytes (first 7 AIDs) to block 0 of MAD Sector 2 (Sector 16 of the Mifare Card)
                    if (objMifare.updateBinaryBlock(0x40, madSector.Take(16).ToArray()) != 0)
                        throw new Exception("Unable to update MAD sector 1");

                    //Write next 16 bytes (next 8 AIDs) to block 1 of MAD Sector 2
                    if (objMifare.updateBinaryBlock(0x41, madSector.Skip(16).Take(16).ToArray()) != 0)
                        throw new Exception("Unable to update MAD sector 1");

                    //Write next 16 bytes (next 8 AIDs) to block 1 of MAD Sector 2
                    if (objMifare.updateBinaryBlock(0x42, madSector.Skip(32).Take(16).ToArray()) != 0)
                        throw new Exception("Unable to update MAD sector 1");
                }

                displayTitle("Change Sector Keys");

                //Update Sector Keys and Access Bits                
                buffer = new byte[16];

                //Key A
                Array.Copy(NDEF_PUBLIC_KEY_A_NFC_FORUM_SECTOR, 0, buffer, 0, 6);

                //Access Bits
                Array.Copy(NDEF_SECTOR_TRAILER_NFC_FORUM_SECTOR, 0, buffer, 6, 4);

                //Key B
                Array.Copy(nfcKeyB, 0, buffer, 10, 6);

                //Update NFC Forum Sector Keys
                //Start from sector 1
                sectorTrailer = 0x03;
                for (int i = 1; i <= numberOfNfcForumSector; i++)
                {
                    if (i <= 31)
                        sectorTrailer += 4;
                    else
                        sectorTrailer += 16;

                    //Check if MAD Sector 2 (Sector 16, Trailer Block = Phycal Block 67)
                    //Skip if MAD Sector 2 trailer
                    if (sectorTrailer == 67)
                    {
                        //Move to next sector trailer
                        sectorTrailer += 4;
                    }

                    if (sectorTrailer < 67)
                        displayMessage("Update Trailer Block of NFC Forum Sector: " + i.ToString());
                    else
                        displayMessage("Update Trailer Block of NFC Forum Sector: " + (i + 1).ToString());

                    if (!objACR122U.authenticate(sectorTrailer, KEYTYPES.ACR122_KEYTYPE_A, 0x00))
                    {
                        throw new Exception("Unable to authenticate in sector: " + i.ToString());
                    }
                    
                    if (objMifare.updateBinaryBlock(sectorTrailer, buffer) != 0)
                        throw new Exception("Unable to update trailer block of sector: " + i.ToString());
                }


                //Update MAD Sector 1 Keys
                displayMessage("Update MAD Sector 1 Trailer");

                if (!objACR122U.authenticate(0x03, KEYTYPES.ACR122_KEYTYPE_A, 0x00))
                    throw new Exception("Unable to authenticate in Mifare Application Directory (MAD) sector 1");

                buffer = new byte[16];

                //Key A
                Array.Copy(NDEF_PUBLIC_KEY_A_MAD_SECTOR, 0, buffer, 0, 6);

                //Access Bits
                Array.Copy(NDEF_SECTOR_TRAILER_MAD_SECTOR, 0, buffer, 6, 4);

                //Key B
                Array.Copy(madKeyB, 0, buffer, 10, 6);

                if (objMifare.updateBinaryBlock(0x03, buffer) != 0)
                    throw new Exception("Unable to update trailer block of MAD Sector 1");

                //If MAD Sector is greater than 15
                //Write the remaining AIDs in the MAD Sector 2
                if (numberOfNfcForumSector > 15)
                {
                    //Update MAD Sector 2 Keys
                    displayMessage("Update MAD Sector 2 Trailer Block");

                    if (!objACR122U.authenticate(0x43, KEYTYPES.ACR122_KEYTYPE_A, 0x00))
                        throw new Exception("Unable to authenticate in Mifare Application Directory (MAD) sector 2");

                    buffer = new byte[16];

                    //Key A
                    Array.Copy(NDEF_PUBLIC_KEY_A_MAD_SECTOR, 0, buffer, 0, 6);

                    //Access Bits
                    Array.Copy(NDEF_SECTOR_TRAILER_MAD_SECTOR, 0, buffer, 6, 4);

                    //Key B
                    Array.Copy(madKeyB, 0, buffer, 10, 6);

                    if (objMifare.updateBinaryBlock(0x43, buffer) != 0)
                        throw new Exception("Unable to update trailer block of MAD Sector 1");

                }
                MessageBox.Show("Write data to tag successfully.", "Write", MessageBoxButtons.OK, MessageBoxIcon.Information);

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + " Data exist in tag. If you want to update please click Reset Card.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void displayMessage(string msg)
        {
            RichTextBoxApduCommandLogs.SelectionFont = new Font("Verdana", 8, FontStyle.Regular);
            RichTextBoxApduCommandLogs.SelectionColor = Color.Black;
            RichTextBoxApduCommandLogs.SelectedText = msg + "\r\n";
            RichTextBoxApduCommandLogs.ScrollToCaret();
        }
        void displayTitle(string title)
        {
            RichTextBoxApduCommandLogs.SelectionFont = new Font("Verdana", 8, FontStyle.Bold);
            RichTextBoxApduCommandLogs.SelectionColor = Color.Black;
            RichTextBoxApduCommandLogs.SelectedText = "\r\n" + title + "\r\n";
            RichTextBoxApduCommandLogs.ScrollToCaret();
        }
        void encodeToNdefUri()
        {
            ACS.NDEF.NdefMessage ndefMessage;
            NdefRecord tmpRecord;
            byte[] buffer;

            //Encode URI
            tmpRecord = new NdefRecord(new NdefRecordType(TypeNameFormat.NfcFormWellKnownType, "U"));

            tmpRecord.messageBegin = true;
            tmpRecord.messageEnd = true;

            //URI Prefix
            //See URI Record Type Definition 
            //http://www.nfc-forum.org
            tmpRecord.appendPayload((byte)((URIIdentifierCode)ComboBoxURIPrefix.SelectedIndex));
            tmpRecord.appendPayload(txtURI.Text);

            ndefMessage = new NdefMessage();
            ndefMessage.appendRecord(tmpRecord);

            //byte[] buffer = NDEF.Ndef.encodeSmartPoster(ComboBoxSmartPosterTitleLanguage.Text,
            //                                           TextBoxSmartPosterTitle.Text,
            //                                           (URIIdentifierCode)ComboBoxSmartPosterPrefixURI.SelectedIndex,
            //                                           TextBoxSmartPosterURI.Text,
            //                                           act);

            buffer = ndefMessage.toByteArray();

            RichTextBoxEncodedNdefMessage.Text = Helper.byteAsString(buffer, false);
        }

        private void TextBoxUriUri_TextChanged(object sender, EventArgs e)
        {
            encodeToNdefUri();
        }

        private void RichTextBoxEncodedNdefMessage_TextChanged(object sender, EventArgs e)
        {
            byte[] buff = Helper.getBytes(RichTextBoxEncodedNdefMessage.Text);

            if (buff == null)
                return;

            labelDataCount.Text = "NDEF Message: (" + buff.Length.ToString() + ")";
        }

        private void ButtonResetCard_Click(object sender, EventArgs e)
        {
            RichTextBoxApduCommandLogs.Text = "";
            resetCard();
        }
        void resetCard()
        {
            try
            {
                Acr1222U objACR122U;
                byte[] madKeyB, nfcKeyB;
                byte[] transportValue = new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x80, 0x69, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
                byte numberOfSectors = 15;
                byte sectorTrailer = 0;


                madKeyB = Helper.getBytes(MaskedTextBoxMadKeyB.Text);
                if (madKeyB.Length != 6)
                {
                    MessageBox.Show("Key-in valid MAD Key B");
                    MaskedTextBoxMadKeyB.Focus();
                    return;
                }

                nfcKeyB = Helper.getBytes(MaskedTextBoxNfcForumSectorKeyB.Text);
                if (nfcKeyB.Length != 6)
                {
                    MessageBox.Show("Key-in valid NFC Forum Sector Key B");
                    MaskedTextBoxNfcForumSectorKeyB.Focus();
                    return;
                }

                objACR122U = new Acr1222U(pcscConnection);

                displayTitle("Get Chip Type");
                CHIP_TYPE chipType = objACR122U.getChipType();
                displayMessage(chipType.ToString() + "\r\n");

                if (chipType != CHIP_TYPE.MIFARE_1K && chipType != CHIP_TYPE.MIFARE_4K)
                {
                    MessageBox.Show("Card not supported");
                    return;
                }

                displayTitle("Load Authentication Keys");

                //Load NFC Forum Sector Secret Key B to device's memory slot number 1
                if (!objACR122U.loadAuthKey(madKeyB, 0x00))
                {
                    MessageBox.Show("Unable to load key", "Load Key Failed");
                    return;
                }

                //Load Mifare Transport Configuration Key (Default Key) to device's memory slot number 2
                if (!objACR122U.loadAuthKey(MIFARE_TRANSPORT_KEY, 0x01))
                {
                    MessageBox.Show("Unable to load key", "Load Key Failed");
                    return;
                }

                displayTitle("Reset MAD Sector 1");


                for (int i = 0; i < 2; i++)
                {
                    //Authenticate using MAD Sector Secret Key B
                    if (i == 0)
                    {
                        if (!objACR122U.authenticate(0x03, KEYTYPES.ACR122_KEYTYPE_B, 0x00))
                            continue;
                    }
                    else
                    {
                        //If failed, assume that the sector is using the transport configuration keys
                        //FF FF FF FF FF FF
                        if (!objACR122U.authenticate(0x03, KEYTYPES.ACR122_KEYTYPE_A, 0x01))
                            continue;
                    }

                    if (objMifare.updateBinaryBlock(0x03, transportValue) == 0)
                        break;
                }

                if (chipType == CHIP_TYPE.MIFARE_4K)
                {
                    displayTitle("Reset MAD Sector 2");

                    for (int i = 0; i < 2; i++)
                    {
                        //Authenticate using MAD Sector Secret Key B
                        if (i == 0)
                        {
                            if (!objACR122U.authenticate(0x63, KEYTYPES.ACR122_KEYTYPE_B, 0x00))
                                continue;
                        }
                        else
                        {
                            //If failed, assume that the sector is using the transport configuration keys
                            //FF FF FF FF FF FF
                            if (!objACR122U.authenticate(0x63, KEYTYPES.ACR122_KEYTYPE_A, 0x01))
                                continue;
                        }

                        if (objMifare.updateBinaryBlock(0x63, transportValue) == 0)
                            break;
                    }

                }

                if (chipType == CHIP_TYPE.MIFARE_4K)
                    numberOfSectors = 39;
                else
                    numberOfSectors = 15;

                for (int i = 1; i <= numberOfSectors; i++)
                {
                    if (i <= 31)
                        sectorTrailer = (byte)((i * 4) + 3);
                    else
                        sectorTrailer = (byte)(128 + ((i - 32) * 16) + 15);

                    displayTitle("Reset Sector: " + i.ToString());

                    if (!objACR122U.authenticate(sectorTrailer, KEYTYPES.ACR122_KEYTYPE_B, 0x00))
                        continue;

                    objMifare.updateBinaryBlock(sectorTrailer, transportValue);
                }
                MessageBox.Show("Reset card successfully.", "Reset card", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btnInitializeCard_Click(object sender, EventArgs e)
        {
            initializeCard();
        }

        private void txtName_TextChanged(object sender, EventArgs e)
        {
            nfc_value(txtName.Text, txtNRIC.Text, txtMobile.Text);
        }

        private void txtNRIC_TextChanged(object sender, EventArgs e)
        {
            nfc_value(txtName.Text, txtNRIC.Text, txtMobile.Text);
        }

        private void txtMobile_TextChanged(object sender, EventArgs e)
        {
            nfc_value(txtName.Text, txtNRIC.Text, txtMobile.Text);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            //string target = "http://www.google.com";
            //System.Diagnostics.Process.Start(target);
            MessageBox.Show(ConvertHexToString(RichTextBoxEncodedNdefMessage.Text));
        }
        public string ConvertHexToString(string HexValue)
        {
            string StrValue = "";
            while (HexValue.Length > 0)
            {
                StrValue += System.Convert.ToChar(System.Convert.ToUInt32(HexValue.Substring(0, 2), 16)).ToString();
                HexValue = HexValue.Substring(2, HexValue.Length - 2);
            }
            return StrValue;
        }
        public string ConvertStringToHex(string asciiString)
        {
            string hex = "";
            foreach (char c in asciiString)
            {
                int tmp = c;
                hex += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(tmp.ToString()));
            }
            return hex;
        }

     
        private void  readFromCard()
        {
            try
            {
                byte numberOfSectors;
                byte currentSector = 1;
                byte physicalBlock = 0;
                byte[] buffer = new byte[0];
                byte[] tmpArray;
                int endIndex = 0;
                int temporaryLen;
                int temporaryPayLoadLen;
                string payLoadTypeNameStr = "";
                NdefMessage ndefMessage;
                NdefMessage temporaryNdefMessage;
                List<NdefRecord> ndefRecords;
                NdefRecord temporaryNdefRecord;

                Acr1222U objACR122U = new Acr1222U(pcscConnection);
                
                displayTitle("Get Chip Type");
                CHIP_TYPE chipType = objACR122U.getChipType();
                displayMessage(chipType.ToString() + "\r\n");

                if (chipType != CHIP_TYPE.MIFARE_1K && chipType != CHIP_TYPE.MIFARE_4K)
                {
                    MessageBox.Show("Card not supported");
                    return ;
                }

                //Load NFC Forum Sector Secret Key B to device's memory slot number 1
                displayMessage("Load MAD Sector Public Key");
                if (!objACR122U.loadAuthKey(NDEF_PUBLIC_KEY_A_MAD_SECTOR, 0x00))
                {
                    MessageBox.Show("Unable to load key", "Load Key Failed");
                    return  ;
                }

                //Load Mifare Transport Configuration Key (Default Key) to device's memory slot number 2
                displayMessage("Load NFC Forum Sector Public Key");
                if (!objACR122U.loadAuthKey(NDEF_PUBLIC_KEY_A_NFC_FORUM_SECTOR, 0x01))
                {
                    MessageBox.Show("Unable to load key", "Load Key Failed");
                    return  ;
                }


                RichTextBoxEncodedNdefMessage.Text = "";

                //Read MAD Sector 1
                //Authenticate using the MAD public key
                //That is previously loaded on thevice
                if (!objACR122U.authenticate(0x01, KEYTYPES.ACR122_KEYTYPE_A, 0x00))
                    throw new Exception("Invalid Card");

                tmpArray = objMifare.readBinaryBlock(0x01);
                buffer = Helper.appendArrays(buffer, tmpArray);

                tmpArray = objMifare.readBinaryBlock(0x02);
                buffer = Helper.appendArrays(buffer, tmpArray);


                if (chipType == CHIP_TYPE.MIFARE_4K)
                {
                    //Read MAD Sector 2

                    //Authenticate using the MAD public key
                    //That is previously loaded on thevice
                    objACR122U.authenticate(0x40, KEYTYPES.ACR122_KEYTYPE_A, 0x00);

                    tmpArray = objMifare.readBinaryBlock(0x40);
                    buffer = Helper.appendArrays(buffer, tmpArray);

                    tmpArray = objMifare.readBinaryBlock(0x41);
                    buffer = Helper.appendArrays(buffer, tmpArray);

                    tmpArray = objMifare.readBinaryBlock(0x42);
                    buffer = Helper.appendArrays(buffer, tmpArray);
                }

                numberOfSectors = 0;

                for (int i = 0; i < buffer.Length; i += 2)
                {
                    if (Helper.byteArrayIsEqual(new byte[] { buffer[i], buffer[i + 1] }, new byte[] { 0x03, 0xE1 }))
                    {
                        numberOfSectors++;
                    }
                }


                buffer = new byte[0];
                currentSector = 1;
                for (int i = 0; i < numberOfSectors; i++)
                {
                    //Skip MAD Sector 2
                    if (currentSector == 16)
                    {
                        currentSector++;
                    }

                    if (currentSector <= 31)
                    {
                        physicalBlock = (byte)(currentSector * 4);
                        objACR122U.authenticate(physicalBlock, KEYTYPES.ACR122_KEYTYPE_A, 0x01);

                        for (int j = 0; j < 3; j++)
                        {
                            tmpArray = objMifare.readBinaryBlock((byte)(physicalBlock + j));
                            buffer = Helper.appendArrays(buffer, tmpArray);
                        }
                    }
                    else
                    {
                        physicalBlock = (byte)(128 + ((currentSector - 32) * 16));
                        objACR122U.authenticate(physicalBlock, KEYTYPES.ACR122_KEYTYPE_A, 0x01);
                        for (int j = 0; j < 15; j++)
                        {
                            tmpArray = objMifare.readBinaryBlock((byte)(physicalBlock + j));
                            buffer = Helper.appendArrays(buffer, tmpArray);
                        }
                    }

                    currentSector++;
                }


                //Check if NDEF Message TAG is present
                if (buffer[0] != (byte)(NFCForum.TAGs.NDEF_MESSAGE_TLV))
                    throw new Exception("NDEF Message TAG is not found");

                //Find the Terminator TLV
                for (endIndex = 0; endIndex < buffer.Length; endIndex++)
                {
                    if (buffer[endIndex] == 0xFE)
                        break;

                    if ((endIndex + 1) >= buffer.Length)
                        throw new Exception("Invalid Card.\r\nTerminator Tag is not found");
                }

                Array.Resize(ref buffer, endIndex);

                //Remove NDEF Message Tag
                //Check if it uses one byte or 3 byte format for the length
                if (buffer[1] == 0xFF)
                {
                    //Uses 3 bytes format
                    tmpArray = new byte[buffer.Length - 4];
                    Array.Copy(buffer, 4, tmpArray, 0, tmpArray.Length);
                }
                else
                {
                    tmpArray = new byte[buffer.Length - 2];
                    Array.Copy(buffer, 2, tmpArray, 0, tmpArray.Length);
                }


                RichTextBoxEncodedNdefMessage.Text = Helper.byteAsString(tmpArray, false);

                ndefMessage = NdefRecord.getNestedNdefMessage(0, tmpArray);

                if (ndefMessage.getNumberOfRecords() < 0)
                {
                    MessageBox.Show("No record to display");
                    return ;
                }

                ndefRecords = ndefMessage.getRecords();

                payLoadTypeNameStr = ndefRecords[0].recordType.typeName;

                if (payLoadTypeNameStr == "Sp")
                {
                    //temporaryNdefMessage = ndefRecords[0].getNestedNdefMessage();

                    //if (temporaryNdefMessage.getNumberOfRecords() < 1)
                    //    throw new Exception("Invalid SmartPoster NDEF Message");

                    ////Get URI Record (Mandatory)
                    //temporaryNdefRecord = temporaryNdefMessage.getRecord(new NdefRecordType(TypeNameFormat.NfcFormWellKnownType, "U"));
                    //if (temporaryNdefRecord == null)
                    //{
                    //    MessageBox.Show("Mandatory URI Record is not found");
                    //    return;
                    //}

                    //ComboBoxSmartPosterPrefixURI.SelectedIndex = temporaryNdefRecord.payLoad[0];
                    //TextBoxSmartPosterURI.Text = ASCIIEncoding.ASCII.GetString(temporaryNdefRecord.payLoad.Skip(1).Take(temporaryNdefRecord.payLoad.Length - 1).ToArray());


                    ////Get Action Record
                    //ComboBoxSmartPosterAction.SelectedIndex = 0;
                    //temporaryNdefRecord = temporaryNdefMessage.getRecord(new NdefRecordType(TypeNameFormat.NfcFormWellKnownType, "act"));
                    //if (temporaryNdefRecord != null)
                    //{
                    //    switch ((NDEF.ActionRecord)temporaryNdefRecord.payLoad[0])
                    //    {
                    //        case ActionRecord.DoTheActon:
                    //            {
                    //                ComboBoxSmartPosterAction.SelectedIndex = 1;
                    //                break;
                    //            }
                    //        case ActionRecord.OpenForEditing:
                    //            {
                    //                ComboBoxSmartPosterAction.SelectedIndex = 2;
                    //                break;
                    //            }
                    //        case ActionRecord.SaveForLater:
                    //            {
                    //                ComboBoxSmartPosterAction.SelectedIndex = 3;
                    //                break;
                    //            }
                    //        default:
                    //            {
                    //                ComboBoxSmartPosterAction.SelectedIndex = 0;
                    //                break;
                    //            }
                    //    }
                    //}
                    //else
                    //{
                    //    ComboBoxSmartPosterAction.SelectedIndex = 0;
                    //}

                    ////Get Text Record
                    //temporaryNdefRecord = temporaryNdefMessage.getRecord(new NdefRecordType(TypeNameFormat.NfcFormWellKnownType, "T"));
                    //if (temporaryNdefRecord != null)
                    //{
                    //    temporaryLen = temporaryNdefRecord.payLoad[0] & 0x1F;
                    //    ComboBoxSmartPosterTitleLanguage.Text = ASCIIEncoding.ASCII.GetString(temporaryNdefRecord.payLoad.Skip(1).Take(temporaryLen).ToArray());

                    //    temporaryPayLoadLen = temporaryNdefRecord.payLoad.Length - (temporaryLen - 1);
                    //    TextBoxSmartPosterTitle.Text = ASCIIEncoding.ASCII.GetString(temporaryNdefRecord.payLoad.Skip(temporaryLen + 1).Take(temporaryPayLoadLen).ToArray());

                    //}


                    //MessageBox.Show("Smart Poster Message Found");
                    //TabControlMain.SelectedIndex = 0;

                }
                else if (payLoadTypeNameStr == "T")
                {
                    ////Get Text Record
                    //temporaryNdefRecord = ndefRecords[0];

                    //if ((temporaryNdefRecord.payLoad[0] & 0x80) != 0x00)
                    //    RadioButtonUtf16.Checked = true;
                    //else
                    //    RadioButtonUtf8.Checked = true;

                    //temporaryLen = temporaryNdefRecord.payLoad[0] & 0x1F;
                    //ComboBoxTextLanguage.Text = ASCIIEncoding.ASCII.GetString(temporaryNdefRecord.payLoad.Skip(1).Take(temporaryLen).ToArray());

                    //temporaryPayLoadLen = temporaryNdefRecord.payLoad.Length - (temporaryLen - 1);
                    //TextBoxTextMessage.Text = ASCIIEncoding.ASCII.GetString(temporaryNdefRecord.payLoad.Skip(temporaryLen + 1).Take(temporaryPayLoadLen).ToArray());

                    //MessageBox.Show("Text Message Found");
                    //TabControlMain.SelectedIndex = 1;

                }
                else if (payLoadTypeNameStr == "U")
                {

                    //None=0
                    //http://www.=1
                    //https://www.=2
                    //http://=3
                    //https://=4
                    //tel:=5
                    //mailto:=6
                    temporaryNdefRecord = ndefRecords[0];
                    //ComboBoxURIPrefix.SelectedIndex = temporaryNdefRecord.payLoad[0];
                    //MessageBox.Show(temporaryNdefRecord.payLoad[0].ToString());
                    int Prefix = temporaryNdefRecord.payLoad[0];
                    String stringPrefix = "";
                    if (Prefix == 0)
                    {
                        stringPrefix = "";
                    }
                    else if (Prefix == 1) { stringPrefix = "http://www."; }
                    else if (Prefix == 2) { stringPrefix = "https://www."; }
                    else if (Prefix == 3) { stringPrefix = "http://"; }
                    else if (Prefix == 4) { stringPrefix = "https://"; }
                    else if (Prefix == 5) { stringPrefix = "tel:"; }
                    else if (Prefix == 6) { stringPrefix = "mailto:"; }
                    lblValueNFCCard.Text = stringPrefix + ASCIIEncoding.ASCII.GetString(temporaryNdefRecord.payLoad.Skip(1).Take(temporaryNdefRecord.payLoad.Length - 1).ToArray());

                    System.Diagnostics.Process.Start(lblValueNFCCard.Text);
                    readStatus = true;
                    //System.Diagnostics.Process.Start(stringPrefix + lblValueNFCCard.Text);
                    //TextBoxUriUri.Text = ASCIIEncoding.ASCII.GetString(temporaryNdefRecord.payLoad.Skip(1).Take(temporaryNdefRecord.payLoad.Length - 1).ToArray());

                    //MessageBox.Show("URI Message Found");
                    //TabControlMain.SelectedIndex = 2;
                    }
                else
                {
                    MessageBox.Show("Unsupported payload type");
                   
                }
               
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message +" Or Card not data.","Error",MessageBoxButtons.OK,MessageBoxIcon.Error );
            }
        }

        private void timerCheckStatus_Tick(object sender, EventArgs e)
        {
            //reloadReaders();
        }
       
     

        private void TimerManager_Tick(object sender, EventArgs e)
        {


            if (reloadReaders() == false)
            {
               // timerCheckReaderStatus.Start();
            }
            if (connectTocard(lblNFCName1.Text) == false)
            {
                lblStatus.Text = "Not tag";
                lblStatus.Image = global::NFC_Tag_Management.Properties.Resources.power_management;
            }
            else
            {
                lblStatus.Text = "Connected successfully";
                lblStatus.Image = global::NFC_Tag_Management.Properties.Resources.ktip;
            }
            
        }

       

      

        private void lblStatus_TextChanged(object sender, EventArgs e)
        {
            if (lblStatus.Text == "Not tag")
            {
                lblValueNFCCard.Text = "";
            }
            else {
                RichTextBoxApduCommandLogs.Text = "";
                readFromCard();
            }
        }

        private void groupBox1_Enter(object sender, EventArgs e)
        {

        }

       

             
        
    }
    }
    
